package com.github.common.extend.demo.config.desensitization.load;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.github.common.extend.demo.config.desensitization.meta.MenuMeta;
import com.github.common.extend.demo.config.desensitization.meta.ResourceMenuMeta;
import com.github.common.extend.demo.config.desensitization.meta.ResourcePropertyMeta;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 从配置文件中读取脱敏字段及展示函数
 * @author wangjj7
 * @date 2023/6/2
 * @description
 */
@Slf4j
@Component
public class ResourceMenuLoader implements MenuLoader {

    private static final String MENU_RESOURCE_PATH = "desensitization/menu.json";

    @Autowired
    private Map<String ,SqlSessionFactory> sqlSessionFactories;

    @Override
    public List<MenuMeta> menuMetas()
    {
        List<ResourceMenuMeta> menuMetas = new ArrayList<>();
        try {
            InputStream inputStream = new ClassPathResource(MENU_RESOURCE_PATH).getInputStream();
            if (inputStream == null){
                log.error("没有找到配置文件{}" ,MENU_RESOURCE_PATH);
                return menuMetas.stream()
                        .map(x -> (MenuMeta) x)
                        .collect(Collectors.toList());
            }
            String properties = IOUtils.toString(inputStream, StandardCharsets.UTF_8.toString());
            log.info("配置文件{}内容：{}" ,MENU_RESOURCE_PATH ,properties);
            menuMetas = JSON.parseObject(properties, new TypeReference<List<ResourceMenuMeta>>(){});
        } catch (IOException e) {
            throw new IllegalStateException("加载解析脱敏数据显示窗口源配置失败");
        }

        for (ResourceMenuMeta menuMeta : menuMetas) {
            List<ResourcePropertyMeta> properties = menuMeta.getProperties();
            if (CollectionUtils.isNotEmpty(properties)){
                for (ResourcePropertyMeta property : properties) {
                    property.setFunction(val -> query(menuMeta.getSqlSessionFactoryBeanName() ,property.getSql(), val));
                }
            }
        }

        return menuMetas.stream()
                .map(x -> (MenuMeta) x)
                .collect(Collectors.toList());
    }

    private String query(String sqlSessionFactoryBeanName ,String sql ,String val)
    {
        if (StringUtils.isBlank(sql)){
            throw new IllegalStateException("没有配置sql，无法查询");
        }
        SqlSession sqlSession = null;
        SqlSessionFactory sqlSessionFactory = null;
        if (StringUtils.isBlank(sqlSessionFactoryBeanName)){
            if (sqlSessionFactories.size() == 1){
                sqlSessionFactory = sqlSessionFactories.values().stream().findAny().orElse(null);
            }
        }else {
            sqlSessionFactory = sqlSessionFactories.get(sqlSessionFactoryBeanName);
        }
        if (sqlSessionFactory == null){
            throw new IllegalStateException("SqlSessionFactory没有指定或不存在");
        }
        try {
            sqlSession = sqlSessionFactory.openSession();
            Connection connection = sqlSession.getConnection();
            connection.setAutoCommit(true);
            Statement statement = connection.createStatement();
            String finalSql = StringUtils.replaceOnce(sql ,"?" ,val);
            log.info("脱敏数据展示窗口查询,{}" ,finalSql);
            ResultSet resultSet = statement.executeQuery(finalSql);
            Object result = null;
            if (resultSet.next()){
                result = resultSet.getObject(1);
            }
            log.info("脱敏数据展示窗口查询结果,{}" ,result);
            return result != null ? result.toString() : null;
        } catch (SQLException e) {
            throw new IllegalStateException("sql执行异常" ,e);
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }

}